﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace LookUpLater
{
    /// <summary>
    /// MainForm
    /// </summary>
    public partial class MainForm : Form
    {
        private List<Lookup> SearchResult;
        private LinkedCustomList<Lookup> Lookups;
        private CustomList<Lookup> CurrentLookup;
        private int TotalItems;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            RefreshAndLoadComponents(this.cbShowDeleted.Checked);
        }

        #region Load Form
        /// <summary>
        /// Displays the lookup.
        /// </summary>
        private void DisplayLookup()
        {
            var lookp = CurrentLookup.Value;
            if (lookp != null)
            {
                this.MainPanel.Controls.OfType<Control>().ToList().ForEach(l => l.Visible = true);
                this.lblCurrentIndex.Text = string.Format("{0} of {1}", CurrentLookup.CurrentIndex + 1, TotalItems);
                this.lblAddedon.Text = lookp.AddedOn.ToString("dd/MM/yyyy HH:mm:ss");
                this.lnkLblLink.Text = lookp.Link.Trim();
                this.lblName.Text = lookp.Name.Trim();
                this.rtbDescription.Text = lookp.Description.Trim();
                this.pbPrevious.Visible = !(CurrentLookup.previousNode.Value == null);
                this.pbNext.Visible = !(CurrentLookup.nextNode.Value == null);
                if (lookp.LookupStatus.status.Equals(Status.Deleted))
                {
                    this.lnkLblActive.Visible = true;
                    this.chbStatus.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F,
                        ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Strikeout))),
                        System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                    this.chbStatus.ForeColor = Color.Gray;
                }
                else
                {
                    this.lnkLblActive.Visible = false;
                    this.chbStatus.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F,
                        ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold))),
                        System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                    this.chbStatus.Checked = lookp.LookupStatus.status.Equals(Status.YetToLookUp);
                }
                //this.MainPanel.Controls.OfType<CheckBox>().ToList().ForEach(l => l.Visible = true);
            }
            else
            {
                //this.MainPanel.Controls.OfType<Label>().ToList().ForEach(l => l.Visible = false);
                //this.MainPanel.Controls.OfType<CheckBox>().ToList().ForEach(l => l.Visible = false);
                //this.pbNext.Visible = false;
                //this.pbPrevious.Visible = false;
                this.MainPanel.Controls.OfType<Control>().ToList().ForEach(c => c.Visible = false);
            }
        }

        /// <summary>
        /// Refreshes the and load components.
        /// </summary>
        private void RefreshAndLoadComponents(bool showDeleted)
        {
            var lookups = LookUpLaterDB.CurrentLookUp.Items.SelectMany(i => i.Lookups).OrderBy(l=>l.AddedOn);
            var filtteredlookups = showDeleted ? lookups.ToList() : lookups.Where(l => !l.LookupStatus.status.Equals(Status.Deleted)).ToList();
            this.Size = new System.Drawing.Size(405, 403);
            this.pbCollapse.Visible = false;
            this.pbExpand.Visible = true;
            this.lblStatus.Text = "Path - " + Directory.GetCurrentDirectory();
            LoadComponents(filtteredlookups);
        }

        /// <summary>
        /// Loads the components.
        /// </summary>
        /// <param name="lookups">The lookups.</param>
        private void LoadComponents(List<Lookup> lookups)
        {
            this.TotalItems = lookups.Count;
            this.Lookups = new LinkedCustomList<Lookup>(lookups);
            this.CurrentLookup = this.Lookups.First;
            DisplayLookup();
        }
        #endregion

        #region TopPanel Operations

        /// <summary>
        /// Handles the Click event of the pbClose control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Handles the Click event of the pbAdd control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbAdd_Click(object sender, EventArgs e)
        {
            this.lblStatus.Text = "Add a new lookup.";
            var result = new AddBox().ShowDialog();
            if (result.Equals(DialogResult.OK))
            {
                this.lblStatus.Text = "New lookup successfully added.";
                RefreshAndLoadComponents(this.cbShowDeleted.Checked);
            }
        }

        /// <summary>
        /// Handles the Click event of the lblAdd control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void lblAdd_Click(object sender, EventArgs e)
        {
            this.pbAdd_Click(sender, e);
        }

        /// <summary>
        /// Handles the Click event of the pbExpand control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbExpand_Click(object sender, EventArgs e)
        {
            this.Size = new Size(573, 403);
            this.pbCollapse.Visible = true;
            this.pbExpand.Visible = false;
        }

        /// <summary>
        /// Handles the Click event of the pbCollapse control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbCollapse_Click(object sender, EventArgs e)
        {
            this.Size = new Size(405, 403);
            this.pbCollapse.Visible = false;
            this.pbExpand.Visible = true;
            RefreshAndLoadComponents(this.cbShowDeleted.Checked);
        }

        /// <summary>
        /// Handles the Click event of the pbDelete control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbDelete_Click(object sender, EventArgs e)
        {
            var currentLookup = this.CurrentLookup.Value;
            if (currentLookup == null)
                return;
            var currentStaus = LookUpStatus.GetStatusById(currentLookup.LookupId);
            currentStaus.status = Status.Deleted;
            currentStaus.SaveOrUpdate();
            this.lblStatus.Text = "Lookup marked as deleted.";
            LookUpLaterDB.Refresh();
            LookUpStatus.Refresh();
            RefreshAndLoadComponents(this.cbShowDeleted.Checked);
        }

        /// <summary>
        /// Handles the Click event of the lblDelete control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void lblDelete_Click(object sender, EventArgs e)
        {
            this.pbDelete_Click(sender, e);
        }

        /// <summary>
        /// Handles the CheckedChanged event of the cbShowDeleted control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void cbShowDeleted_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox chb = (CheckBox)sender;
            RefreshAndLoadComponents(chb.Checked);
        }
        #endregion

        #region SidePanel

        /// <summary>
        /// Handles the LinkClicked event of the lnkLblLink control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.LinkLabelLinkClickedEventArgs"/> instance containing the event data.</param>
        private void lnkLblLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            //Open the link in default system process.
            // if Url, then opened by IE , FF... (in default browser).
            // if local pdf, then opened by PDF Viewer.

            //Invalid path is caught and not processed.
            try
            {
                if (!string.IsNullOrWhiteSpace(this.lnkLblLink.Text))
                {
                    System.Diagnostics.Process.Start(this.lnkLblLink.Text);
                }
            }
            catch { }
        }

        /// <summary>
        /// Handles the TextChanged event of the tbSearch control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tbSearch_TextChanged(object sender, EventArgs e)
        {
            this.SearchResult = LookUpLaterDB.CurrentLookUp.Items.SelectMany(i => i.Lookups).Where(l => l.Name.ToLower().Contains(this.tbSearch.Text.ToLower())).ToList();
            this.SidePanel.Controls.OfType<SearchResultComponent>().ToList().ForEach(l => l.Dispose());
            PopulateSearchResultPanel();
        }

        /// <summary>
        /// Populates the search result panel.
        /// </summary>
        private void PopulateSearchResultPanel()
        {
            List<SearchResultComponent> compList = new List<SearchResultComponent>();
            int defaultY = 50;
            int defaultX = 4;
            int defaultWidth = 15;
            if (this.SearchResult.Count > 0)
            {
                for (int i = 0; i < this.SearchResult.Count; i++)
                {
                    var l = this.SearchResult[i];
                    var srComp = new SearchResultComponent(l.Name, l.LookupId, defaultX, (i * defaultWidth + defaultY));
                    srComp.Click += new EventHandler(srComp_Click);
                    srComp.lblSearchLookupName.Click += new EventHandler(lblSearchLookupName_Click);
                    compList.Add(srComp);
                }
            }
            else
            {
                compList.Add(new SearchResultComponent("No results found.", "0000", defaultX, defaultY));
            }

            this.SidePanel.Controls.AddRange(compList.ToArray());
        }

        /// <summary>
        /// Handles the Click event of the lblSearchLookupName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void lblSearchLookupName_Click(object sender, EventArgs e)
        {
            var srComp = (SearchResultComponent)((Label)sender).Parent;
            LoadLookUpToMainComponent(srComp);
        }

        /// <summary>
        /// Handles the Click event of the srComp control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void srComp_Click(object sender, EventArgs e)
        {
            var srComp = (SearchResultComponent)sender;
            LoadLookUpToMainComponent(srComp);
        }
        #endregion

        #region MainPanel
        /// <summary>
        /// Handles the Click event of the chbStatus control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void chbStatus_Click(object sender, EventArgs e)
        {
            LookUpStatus currentLookupstatus = this.CurrentLookup.Value.LookupStatus;
            Status changeToStatus = currentLookupstatus.status.Equals(Status.YetToLookUp) ? Status.LookedUp : Status.YetToLookUp;
            currentLookupstatus.status = changeToStatus;
            currentLookupstatus.SaveOrUpdate();
        }

        /// <summary>
        /// Loads the look up to main component.
        /// </summary>
        /// <param name="srComp">The sr comp.</param>
        private void LoadLookUpToMainComponent(SearchResultComponent srComp)
        {
            Lookup lup = LookUpLaterDB.CurrentLookUp.Items.SelectMany(s => s.Lookups).First(l => l.LookupId.Equals(srComp.lookupId));
            LoadComponents(new List<Lookup> { lup });
        }

        /// <summary>
        /// Handles the Click event of the pbNext control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbNext_Click(object sender, EventArgs e)
        {
            this.CurrentLookup = CurrentLookup.nextNode;
            DisplayLookup();
        }

        /// <summary>
        /// Handles the Click event of the pbPrevious control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbPrevious_Click(object sender, EventArgs e)
        {
            this.CurrentLookup = CurrentLookup.previousNode;
            DisplayLookup();
        }

        /// <summary>
        /// Handles the LinkClicked event of the lnkLblActive control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.LinkLabelLinkClickedEventArgs"/> instance containing the event data.</param>
        private void lnkLblActive_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            var lnkLbl = (LinkLabel)sender;
            lnkLbl.Visible = false;
            LookUpStatus currentLookupstatus = this.CurrentLookup.Value.LookupStatus;
            currentLookupstatus.status = Status.LookedUp;
            currentLookupstatus.SaveOrUpdate();
            this.chbStatus.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F,
                        ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold))),
                        System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.chbStatus.ForeColor = Color.Black;
            this.chbStatus.Checked = currentLookupstatus.status.Equals(Status.YetToLookUp);
        }
        #endregion

        #region Filter Operation
        /// <summary>
        /// Handles the SelectedIndexChanged event of the cbFilterBy control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void cbFilterBy_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.cbFilterBy.SelectedItem != null)
            {
                var selectedItem = this.cbFilterBy.SelectedItem.ToString();
                object[] filterContainsItems = null;
                switch (selectedItem)
                {
                    case "Type":
                        filterContainsItems = GetNamesbyType();
                        break;
                    case "SubCategory":
                        filterContainsItems = GetNamesbySubCategory();
                        break;
                    case "Group":
                        filterContainsItems = GetNamesbyGroup();
                        break;
                }
                this.cbFilterContains.Items.Clear();
                this.cbFilterContains.Items.AddRange(filterContainsItems);
            }
        }

        /// <summary>
        /// Gets the namesby group.
        /// </summary>
        /// <returns></returns>
        private object[] GetNamesbyGroup()
        {
            return LookUpLaterDB.CurrentLookUp.Items.Select(i => i.Group.Name).Distinct().ToArray();
        }

        /// <summary>
        /// Gets the namesby sub category.
        /// </summary>
        /// <returns></returns>
        private object[] GetNamesbySubCategory()
        {
            return LookUpLaterDB.CurrentLookUp.Items.Select(i => i.SubCategory.Name).Distinct().ToArray();
        }

        /// <summary>
        /// Gets the type of the namesby.
        /// </summary>
        /// <returns></returns>
        private object[] GetNamesbyType()
        {
            return LookUpLaterDB.CurrentLookUp.Items.Select(i => i.LookupType.Name).Distinct().ToArray();
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the cbFilterContains control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void cbFilterContains_SelectedIndexChanged(object sender, EventArgs e)
        {
            var selectedBy = this.cbFilterBy.SelectedItem;
            var selectedContains = this.cbFilterContains.SelectedItem;
            if (selectedBy != null || selectedContains != null)
            {
                var selectedByText = selectedBy.ToString();
                var selectedContainsText = selectedContains.ToString();
                List<Lookup> filterContainsItems = null;
                switch (selectedByText)
                {
                    case "Type":
                        filterContainsItems = GetLookupsbyType(selectedContainsText);
                        break;
                    case "SubCategory":
                        filterContainsItems = GetLookupsbySubCategory(selectedContainsText);
                        break;
                    case "Group":
                        filterContainsItems = GetLookupsbyGroup(selectedContainsText);
                        break;
                }
                LoadComponents(filterContainsItems);
            }
        }

        /// <summary>
        /// Gets the lookupsby group.
        /// </summary>
        /// <param name="selectedContainsText">The selected contains text.</param>
        /// <returns></returns>
        private List<Lookup> GetLookupsbyGroup(string selectedContainsText)
        {
            return LookUpLaterDB.CurrentLookUp.Items.Where(i => i.Group.Name.Contains(selectedContainsText)).SelectMany(i => i.Lookups).ToList();
        }

        /// <summary>
        /// Gets the lookupsby sub category.
        /// </summary>
        /// <param name="selectedContainsText">The selected contains text.</param>
        /// <returns></returns>
        private List<Lookup> GetLookupsbySubCategory(string selectedContainsText)
        {
            return LookUpLaterDB.CurrentLookUp.Items.Where(i => i.SubCategory.Name.Contains(selectedContainsText)).SelectMany(i => i.Lookups).ToList();
        }

        /// <summary>
        /// Gets the type of the lookupsby.
        /// </summary>
        /// <param name="selectedContainsText">The selected contains text.</param>
        /// <returns></returns>
        private List<Lookup> GetLookupsbyType(string selectedContainsText)
        {
            return LookUpLaterDB.CurrentLookUp.Items.Where(i => i.LookupType.Name.Contains(selectedContainsText)).SelectMany(i => i.Lookups).ToList();
        }
        #endregion

        #region Refresh
        /// <summary>
        /// Handles the Click event of the pbRefresh control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pbRefresh_Click(object sender, EventArgs e)
        {
            RefreshAndLoadComponents(this.cbShowDeleted.Checked);
        }

        /// <summary>
        /// Handles the Click event of the lblRefresh control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void lblRefresh_Click(object sender, EventArgs e)
        {
            pbRefresh_Click(sender, e);
        }
        #endregion


    }
}
